package jmine.tec.web.wicket.exception;

import jmine.tec.web.servlet.filter.TransactionFilter;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.wicket.Session;

import bancosys.tec.exception.BusinessException;
import bancosys.tec.exception.LocalizedMessageHolder;
import bancosys.tec.exception.informer.UserFriendlyExceptionInformer;
import bancosys.tec.rtm.impl.RtmController;

/**
 * Exception handler that marks the transaction for rollback and tries to give the user a good feedback message.
 * 
 * @author lundberg
 */
public class FeedbackExceptionHandler implements ExceptionHandler {

    private RtmController rtmController;

    private UserFriendlyExceptionInformer userFriendlyExceptionInformer;

    /**
     * {@inheritDoc}
     */
    public void handle(Exception e) {
        this.markTransactionForRollback();
        this.setThreadInterruptStatus(e);
        this.monitor(e);
        this.setUserFeedbackMessages(e);
    }

    /**
     * Marks the current request transaction for rollback.
     */
    private void markTransactionForRollback() {
        TransactionFilter.markCurrentTransactionRollbackOnly();
    }

    /**
     * If this exception was caused by an interrupt request, sets the thread's interrupt status.
     * 
     * @param e exception
     */
    private void setThreadInterruptStatus(Exception e) {
        for (Throwable t : ExceptionUtils.getThrowables(e)) {
            if (t instanceof InterruptedException) {
                Thread.currentThread().interrupt();
                return;
            }
        }
    }

    /**
     * Logs the exception, if relevant
     * 
     * @param e exception
     */
    protected void monitor(Exception e) {
        if (this.isRelevant(e)) {
            this.rtmController.monitor(e);
        }
    }

    /**
     * Checks if this exception is relevant and should be logged.
     * 
     * @param e e
     * @return boolean
     */
    protected boolean isRelevant(Exception e) {
        Throwable[] chain = ExceptionUtils.getThrowables(e);
        return !(chain[chain.length - 1] instanceof BusinessException);
    }

    /**
     * Defines user friendly messages as feedback.
     * 
     * @param e exception
     */
    protected void setUserFeedbackMessages(Exception e) {
        for (LocalizedMessageHolder message : this.userFriendlyExceptionInformer.getUserFriendlyMessages(e)) {
            Session.get().getFeedbackMessages().error(null, message.getMessage());
        }
        Session.get().dirty();
    }

    /**
     * @param rtmController the rtmController to set
     */
    public void setRtmController(RtmController rtmController) {
        this.rtmController = rtmController;
    }

    /**
     * @param userFriendlyExceptionInformer the userFriendlyExceptionInformer to set
     */
    public void setUserFriendlyExceptionInformer(UserFriendlyExceptionInformer userFriendlyExceptionInformer) {
        this.userFriendlyExceptionInformer = userFriendlyExceptionInformer;
    }
}
